package com.nbsaas.boot;

import javax.script.*;
import java.io.File;
import java.io.FileReader;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 动态 Groovy 脚本执行引擎，支持文件变更自动重新编译
 */
public class FileScriptEngine {

    // 缓存脚本
    private final Map<String, CachedScript> cache = new ConcurrentHashMap<>();

    // Groovy 脚本引擎（通过 JSR-223 获取）
    private final ScriptEngine engine;

    public FileScriptEngine() {
        // 注意：避免与 javax.script.ScriptEngineManager 混淆
        javax.script.ScriptEngineManager factory = new javax.script.ScriptEngineManager();
        this.engine = factory.getEngineByName("groovy");
        if (!(engine instanceof Compilable)) {
            throw new IllegalStateException("当前脚本引擎不支持编译（需要 Groovy ScriptEngine 支持）");
        }
    }

    /**
     * 执行指定路径的 Groovy 脚本文件
     */
    public Object execute(String path) throws Exception {
        File file;
        URL resource = getClass().getClassLoader().getResource(path);

        if (resource != null) {
            // 从类路径加载
            file = new File(resource.toURI());
        } else {
            // 如果不是类路径资源，就尝试当作系统文件路径
            file = new File(path);
        }

        if (!file.exists()) {
            throw new IllegalArgumentException("脚本文件不存在: " + path);
        }

        long lastModified = file.lastModified();

        CachedScript cached = cache.get(path);
        if (cached == null || cached.timestamp < lastModified) {
            cached = new CachedScript(compile(file), lastModified);
            cache.put(path, cached);
        }

        return cached.script.eval();
    }

    /**
     * 编译 Groovy 脚本文件
     */
    private CompiledScript compile(File file) throws Exception {
        Compilable compilable = (Compilable) engine;
        try (FileReader reader = new FileReader(file)) {
            return compilable.compile(reader);
        }
    }

    /**
     * 缓存封装
     */
    private static class CachedScript {
        final CompiledScript script;
        final long timestamp;

        CachedScript(CompiledScript script, long timestamp) {
            this.script = script;
            this.timestamp = timestamp;
        }
    }
}
